package com.yds.ydsdatasetbackend.service.impl;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.ObjUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.yds.ydsdatasetbackend.exception.BusinessException;
import com.yds.ydsdatasetbackend.exception.ErrorCode;
import com.yds.ydsdatasetbackend.exception.ThrowUtils;
import com.yds.ydsdatasetbackend.manager.rabbitmq.train.MyFileTrainProducer;
import com.yds.ydsdatasetbackend.model.dto.file.predict.*;
import com.yds.ydsdatasetbackend.model.entity.*;
import com.yds.ydsdatasetbackend.model.enums.FileTrainEnum;
import com.yds.ydsdatasetbackend.model.vo.FilePredictVO;
import com.yds.ydsdatasetbackend.model.vo.FileTrainVO;
import com.yds.ydsdatasetbackend.service.FilePredictService;
import com.yds.ydsdatasetbackend.mapper.FilePredictMapper;
import com.yds.ydsdatasetbackend.service.FileTrainService;
import com.yds.ydsdatasetbackend.service.FileVariablesService;
import com.yds.ydsdatasetbackend.service.UserService;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.util.*;
import java.util.stream.Collectors;

/**
* @author YDS
* @description 针对表【file_predict(文件预测变量表)】的数据库操作Service实现
* @createDate 2025-02-09 18:04:56
*/
@Service
public class FilePredictServiceImpl extends ServiceImpl<FilePredictMapper, FilePredict>
    implements FilePredictService{

    @Resource
    private UserService userService;

    @Resource
    @Lazy
    private FileTrainService fileTrainService;

    @Resource
    private MyFileTrainProducer myFileTrainProducer;

    @Resource
    private FileVariablesService fileVariablesService;

    @Override
    public FilePredictVO addFilePredict(FilePredictAddRequest filePredictAddRequest, User loginUser) {
        // 1. 参数检验
        Long trainId = filePredictAddRequest.getTrainId();
        String introduction = filePredictAddRequest.getIntroduction();
        List<FilePredictInputParams> predictParams = filePredictAddRequest.getPredictParams();

        if (trainId == null) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR);
        }
        FileTrain fileTrain = fileTrainService.getById(trainId);
        ThrowUtils.throwIf(fileTrain == null, ErrorCode.NOT_FOUND_ERROR, "训练不存在");
        ThrowUtils.throwIf( StrUtil.isNotBlank(introduction) && introduction.length() > 1024, ErrorCode.PARAMS_ERROR, "introduction过长");
        ThrowUtils.throwIf(!loginUser.getId().equals(fileTrain.getUserId()), ErrorCode.NO_AUTH_ERROR, "没有权限");
        // 对传入的预测参数对列进行排序
        predictParams.sort(Comparator.comparing(FilePredictInputParams::getColumnNumber));

//        List<Double> paramList = predictParams.stream().map(FilePredictInputParams::getParam).collect(Collectors.toList());
        // 2.填写参数
        FilePredict filePredict = new FilePredict();
        filePredict.setFileId(fileTrain.getFileId());
        filePredict.setTrainId(trainId);
        filePredict.setIntroduction(introduction);
        filePredict.setPredictStatus(FileTrainEnum.WAITING.getValue());
        filePredict.setPredictParams(JSONUtil.toJsonStr(predictParams));
        boolean saved = this.save(filePredict);
        ThrowUtils.throwIf(!saved, ErrorCode.OPERATION_ERROR, "预测文件创建失败");


        // 发送请求给rabbitmq,让它处理信息
        Long predictId = filePredict.getId();
        myFileTrainProducer.sendMessage("file_exchange","my_routingKey2", String.valueOf(predictId));


        return getFilePredictVO(filePredict, null);
    }


    @Override
    public void editFilePredict(FilePredictEditRequest filePredictEditRequest, User loginUser) {
        // 在此处将实体类和 DTO 进行转换
        FilePredict filePredict = this.getById(filePredictEditRequest.getId());
        ThrowUtils.throwIf(filePredict == null, ErrorCode.NOT_FOUND_ERROR);
        // 校验权限
        FileTrain fileTrain = fileTrainService.getById(filePredict.getTrainId());
        fileTrainService.checkFileTrainAuth(loginUser, fileTrain);
        // 更新
        filePredict.setIntroduction(filePredictEditRequest.getIntroduction());
        // 操作数据库
        boolean result = this.updateById(filePredict);
        ThrowUtils.throwIf(!result, ErrorCode.OPERATION_ERROR);
    }

    @Override
    public FilePredictVO getFilePredictVO(FilePredict filePredict, HttpServletRequest request) {
        // 对象转封装类
        FilePredictVO filePredictVO = FilePredictVO.objToVo(filePredict);

//        // 查询对应变量名称
        Long trainId = filePredict.getTrainId();
        FileTrain fileTrain = fileTrainService.getById(trainId);
//        Long fileId = fileTrain.getFileId();
//        List<FilePredictInputParams> paramsList = JSONUtil.toList(filePredict.getPredictParams(), FilePredictInputParams.class);

//        Map<Long, List<FileVariables>> columnVariablesListMap = fileVariablesService.lambdaQuery()
//                .eq(FileVariables::getFileId,fileId).list().stream().collect(Collectors.groupingBy(FileVariables::getColumnNumber));
//
//        List<FilePredictOutputParams> filePredictOutputList = new ArrayList<>();
//        for (FilePredictInputParams filePredictInputParams : paramsList) {
//            Long columnNumber = filePredictInputParams.getColumnNumber();
//            Double param = filePredictInputParams.getParam();
//
//            FilePredictOutputParams filePredictOutputParams = new FilePredictOutputParams();
//            filePredictOutputParams.setColumnNumber(columnNumber);
//            filePredictOutputParams.setParam(param);
//            // 变量数据表的collumn是从1开始，而其余从0开始
//            if(columnVariablesListMap.containsKey(columnNumber + 1)){
//                filePredictOutputParams.setVariablesName(columnVariablesListMap.get(columnNumber + 1).get(0).getName());
//            }
//            filePredictOutputList.add(filePredictOutputParams);
//        }

//        filePredictVO.setPredictParams(filePredictOutputList);


        // 关联查询训练信息
        if (trainId != null && trainId > 0) {
            FileTrainVO fileTrainVO = fileTrainService.getFileTrainVO(fileTrain, request);
            filePredictVO.setFileTrain(fileTrainVO);
        }
        return filePredictVO;
    }

    /**
     * 分页获取图片封装,将获取到的页进行脱敏
     */
    @Override
    public Page<FilePredictVO> getFilePredictVOPage(Page<FilePredict> filePredictPage, HttpServletRequest request) {
        List<FilePredict> filePredictList = filePredictPage.getRecords();
        Page<FilePredictVO> filePredictVOPage = new Page<>(filePredictPage.getCurrent(), filePredictPage.getSize(), filePredictPage.getTotal());
        if (CollUtil.isEmpty(filePredictList)) {
            return filePredictVOPage;
        }
        // 对象列表 => 封装对象列表
        List<FilePredictVO> filePredictVOList = filePredictList.stream().map(FilePredictVO::objToVo).collect(Collectors.toList());
        // 1. 关联查询训练信息

        Set<Long> trainIdSet = filePredictList.stream().map(FilePredict::getTrainId).collect(Collectors.toSet());
        Map<Long, List<FileTrain>> trainIdFileTrainListMap = fileTrainService.listByIds(trainIdSet).stream()
                .collect(Collectors.groupingBy(FileTrain::getId));
        // 2. 填充信息
        filePredictVOList.forEach(filePredictVO -> {
            Long trainId = filePredictVO.getTrainId();
            FileTrain fileTrain = null;
            if (trainIdFileTrainListMap.containsKey(trainId)) {
                fileTrain = trainIdFileTrainListMap.get(trainId).get(0);
            }
            filePredictVO.setFileTrain(fileTrainService.getFileTrainVO(fileTrain, request));

        });
        filePredictVOPage.setRecords(filePredictVOList);
        return filePredictVOPage;
    }

    /**
     * 分页获取图片包装
     *
     * @param filePredictQueryRequest
     * @return
     */
    @Override
    public QueryWrapper<FilePredict> getQueryWrapper(FilePredictQueryRequest filePredictQueryRequest) {
        QueryWrapper<FilePredict> queryWrapper = new QueryWrapper<>();
        if (filePredictQueryRequest == null) {
            return queryWrapper;
        }
        // 从对象中取值
        Long id = filePredictQueryRequest.getId();
        Long trainId = filePredictQueryRequest.getTrainId();
        String introduction = filePredictQueryRequest.getIntroduction();
        String predictStatus = filePredictQueryRequest.getPredictStatus();
        Date startCreateTime = filePredictQueryRequest.getStartCreateTime();
        Date endCreateTime = filePredictQueryRequest.getEndCreateTime();
        String sortField = filePredictQueryRequest.getSortField();
        String sortOrder = filePredictQueryRequest.getSortOrder();


        queryWrapper.eq(ObjUtil.isNotEmpty(id), "id", id);
        queryWrapper.eq(ObjUtil.isNotEmpty(trainId), "trainId", trainId);
        queryWrapper.like(StrUtil.isNotBlank(introduction), "introduction", introduction);
        queryWrapper.eq(StrUtil.isNotBlank(predictStatus), "predictStatus", predictStatus);
        queryWrapper.ge(ObjUtil.isNotEmpty(startCreateTime), "createTime", startCreateTime);
        queryWrapper.lt(ObjUtil.isNotEmpty(endCreateTime), "createTime", endCreateTime);
        // 排序
        queryWrapper.orderBy(StrUtil.isNotEmpty(sortField), sortOrder.equals("ascend"), sortField);
        return queryWrapper;
    }

    /**
     * 删除文件
     * @param filePredictId
     * @param loginUser
     */
    @Override
    public void deleteFilePredict(long filePredictId, User loginUser) {
        ThrowUtils.throwIf(filePredictId <= 0, ErrorCode.PARAMS_ERROR);
        ThrowUtils.throwIf(loginUser == null, ErrorCode.NO_AUTH_ERROR);
        // 判断是否存在
        FilePredict filePredict = this.getById(filePredictId);
        ThrowUtils.throwIf(filePredict == null, ErrorCode.NOT_FOUND_ERROR);
        // 校验权限
        Long trainId = filePredict.getTrainId();
        FileTrain fileTrain = fileTrainService.getById(trainId);
        fileTrainService.checkFileTrainAuth(loginUser, fileTrain);

        boolean result = this.removeById(filePredict);
        ThrowUtils.throwIf(!result, ErrorCode.OPERATION_ERROR);
    }

}




